package com.rafaelGarcia.eLibreria.db;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

public class ControladorDB {
	
	private static ControladorDB control = null;
	private static Set<String> clasesMapeadas;
	private static SessionFactory sF;
	
	
	private ControladorDB(){
		sF = GestorDB.getSessionFactory();
		
		clasesMapeadas = sF.getAllClassMetadata().keySet();
	}
	
	private static void iniciar(){
		if (control == null){
			control = new ControladorDB();
		}
	}
	
	public static <T> boolean insertar(T objeto){
		iniciar();
		
		//Inserta un objeto de una clase mapeada en la BD.		
		boolean res = false;
		
		if(claseMapeada(objeto.getClass())){
			res = insercion(objeto);
		}
		
		return res;
	}
	
	public static <T> boolean insertar(List<T> listT){
		iniciar();

		//Devolvera true siempre que consiga insertar al menos un registro de la lista
		boolean res = false;
		
		for(T objeto: listT){
			if(claseMapeada(objeto.getClass())){
				res |= insercion(objeto);
			}
		}
				
		return res;
	}
	
	@SuppressWarnings("unchecked")
	public static <T, S extends T> T getObjeto(Class<S> c, Long id){
		iniciar();
		T res = null;
		
		if(claseMapeada(c)){
			Session s = null;
			Transaction tx = null;
			
			try{
				s = sF.openSession();
				tx = s.beginTransaction();
				
				res = (S) s.get(c, id);
				
				tx.commit();
			}
			catch(Exception ex){
				ex.printStackTrace();
				tx.rollback();
			}
			finally{
				s.close();
			}
		}
		
		return res;
	}
	
	public static <T> void actualizar(T obj){
		iniciar();
		
		if(claseMapeada(obj.getClass())){
			update(obj);
		}	
	}
	
	public static <T> void actualizar(List<T> obj){
		iniciar();
		
		if(claseMapeada(obj.getClass())){
			for(T o: obj){
				update(o);
			}
		}	
	}
	
	private static <T> void update(T obj){
		Session s = null;
		Transaction tx = null;
		
		try{
			s = sF.openSession();
			tx = s.beginTransaction();
			
			s.update(obj);
			
			tx.commit();
		}
		catch(Exception ex){
			ex.printStackTrace();
			tx.rollback();
		}
		finally{
			s.close();
		}
	}

	public static <T, S extends T> List<T> getTodos(Class<S> c){
		iniciar();
		
		List<T> res = new ArrayList<T>();
		
		if(claseMapeada(c)){
			Session s = null;
			Transaction tx = null;
		
			try{
				s = sF.openSession();
				tx = s.beginTransaction();
				
				@SuppressWarnings("unchecked")
				List<S> aux = s.createQuery("FROM " + c.getName()).list();
				
				for(S o: aux){
					res.add((T) o);
				}
				
				tx.commit();				
			}
			catch(Exception ex){
				ex.printStackTrace();
				tx.rollback();
			}
			finally{
				s.close();
			}
		}
		
		return res;
	}
	
	public static Integer contarResultados(String HQL){
		iniciar();
		
		Integer res = null;
		
		Session s = null;
		Transaction tx = null;
		
		try{
			s = sF.openSession();
			tx = s.beginTransaction();
			
			Object result = s.createQuery(HQL).uniqueResult();
			
			if(result == null){
				res = 0;
			}
			else{
				res = ((Long) result).intValue();
			}
			
			tx.commit();
		}
		catch(Exception ex){
			ex.printStackTrace();
			tx.rollback();
		}
		finally{
			s.close();
		}
		
		return res;
	}
	
	public static <T> Integer numElementos(Class<T> c){
		iniciar();
		
		return contarResultados("select count(*) from " + c.getName());
	}
	
	public static <T> void vaciarEntidad(Class<T> c){
		iniciar();
		
		Session s = null;
		Transaction tx = null;
		
		if(claseMapeada(c)){
			try{
				s = sF.openSession();
				tx = s.beginTransaction();
				
				s.createQuery("delete " + c.getName()).executeUpdate();
				
				tx.commit();
				
			}
			catch(Exception ex){
				ex.printStackTrace();
				tx.rollback();
			}
			finally{
				s.close();
			}
		}
	}
	
	private static <T> boolean insercion(T objeto){	
		boolean res = false;
		Session s = null;
        Transaction tx = null;
        
        try{        
	        s = sF.openSession();
	        tx= s.beginTransaction();
	         
	        // Saving to the database
	        s.save(objeto);
	         
	        // Committing the change in the database.
	        s.flush();
	        tx.commit();
	        res = true;
        }
        catch(Exception ex){
        	ex.printStackTrace();
        	tx.rollback();
        }
        finally{
        	s.close();
        }
        
        return res;
	}

	private static <T> boolean claseMapeada(Class<T> c){
		return clasesMapeadas.contains(c.getName());
	}
}
